`timescale 1ns / 1ps
/*--------------------------------------------------------------------*\
FileName        : cbb_dpram_2.v
Author          ：hpy
Email           ：yuan_hp@qq.com
Date            ：2024年01月07日
Description     ：

cbb_dpram_sclk
#(
    .ADDR_WIDTH    ( 8   )  ,    // 地址位宽
    .DATA_WIDTH    ( 8   )  ,    // 数据位宽
	.DATA_DEPTH    ( 256 )  ,    // 数据数量
    .CLEAR_ON_INIT ( 1   )  ,    // 是否清零
    .ENABLE_BYPASS ( 1   )  ,    // 为1时:写和读同时有效时，读的数据就是写的数据
    .ENABLE_ASYNC  ( 0   )       // 1:异步RAM
) 
u_cbb_dpram_sclk
(
    .clk      () ,
    .rst      () ,
    .raddress () ,
    .waddress () ,
    .re       () ,
    .we       () ,
    .i_data   () ,
    .o_data   () 
);

\*--------------------------------------------------------------------*/
module cbb_dpram
#(
    parameter ADDR_WIDTH = 8,    // 地址位宽
    parameter DATA_WIDTH = 8,    // 数据位宽
	parameter DATA_DEPTH = 256,  // 数据数量
    parameter CLEAR_ON_INIT = 1, // 是否清零
    parameter ENABLE_BYPASS = 1, // 为1时:写和读同时有效时，读的数据就是写的数据
    parameter ENABLE_ASYNC  = 0  // 1:异步
)
(
    clk,
    rst,
    raddress,
    re,
    waddress,
    we,
    i_data,
    o_data
);

/*
 Ports
 */
input                           clk;
input                           rst;
input [ADDR_WIDTH-1:0]          raddress;
input                           re;
input [ADDR_WIDTH-1:0]          waddress;
input                           we;
input [DATA_WIDTH-1:0]          i_data;
output [DATA_WIDTH-1:0]         o_data;
    
/*
 Internals
 */
(* ram_style="block_ram" *) reg [DATA_WIDTH-1:0]            mem[DATA_DEPTH-1:0]  /* synthesis syn_ramstyle = "block_ram" */;
reg [DATA_WIDTH-1:0]            rdata;
reg                             re_r;
wire [DATA_WIDTH-1:0]           o_data_w;

    /*
     reset in verification
     */
generate
  if(CLEAR_ON_INIT) begin :clear_on_init
    integer               idx;
    initial
    for(idx=0; idx < DATA_DEPTH; idx=idx+1)
        mem[idx] = {DATA_WIDTH{1'b0}};
  end
endgenerate

    /*
     bypass control
     */
generate

  if(|ENABLE_ASYNC) begin : asyc_bypass_gen 
    if (ENABLE_BYPASS) begin : bypass_gen1
        assign o_data_w = (waddress == raddress && we && re) ? i_data : rdata;
    end else begin
        assign o_data_w = rdata;
    end
  end else begin : sync_bypass_gen
    if (ENABLE_BYPASS) begin : bypass_gen
        reg [DATA_WIDTH-1:0]  i_data_r;
        reg                   bypass;

        assign o_data_w = bypass ? i_data_r : rdata;

        always @(posedge clk)
            if (re)
                i_data_r <= i_data;

        always @(posedge clk)
            if (waddress == raddress && we && re)
                bypass <= 1;
            else
                bypass <= 0;
    end else begin
        assign o_data_w = rdata;
    end
  end 
endgenerate



/*
 Reset logic
 */

generate 
    genvar i , j , k  ;
    if(|ENABLE_ASYNC) begin : ASYC_BLK

        for(k=0;k<DATA_WIDTH;k=k+1) begin : asyc_read_blk        
        
			  /*
			  R logic
			  */
			  always @* begin
					if (re)
						 rdata[k] = mem[raddress][k];
					else
						 rdata[k] = 1'b0;
			  end

			  /*
			  W logic
			  */
			  always @(posedge clk) begin
					if (we)
						 mem[waddress][k] <= i_data[k];
			  end
		  end

        for(j=0;j<DATA_WIDTH;j=j+1) begin :asyc_out_blk
            assign o_data[j] = re ? o_data_w[j] : 1'b0;
        end

    end else begin : SYNC_BLK
        always @(posedge clk)begin 
            if (rst) begin
                re_r <= 1'b0;
            end else begin 
                re_r <= re;
            end 
        end 

        /*
        R/W logic
        */
        always @(posedge clk) begin
            if (we)
                mem[waddress] <= i_data;
            if (re)
                rdata <= mem[raddress];
        end

        for(i=0;i<DATA_WIDTH;i=i+1) begin  :sync_out_blk
            assign o_data[i] = re_r ? o_data_w[i] : 1'b0;
        end
    end 
endgenerate 

endmodule
 
 
 
